﻿using System;
using System.Linq;
using System.Net;
using System.IO;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Practices.Prism.Regions;
using Microsoft.Practices.Prism.Events;
using Microsoft.Practices.Prism.Commands;
using Microsoft.Practices.Unity;
using DXTools.UI.Core;
using DXTools.UI.Modules.MetadataBrowser.Views;
using DXTools.UI.Core.Events;
using System.Collections.Generic;
using DXTools.UI.Modules.MetadataBrowser.Model;
using DXTools.UI.Modules.MetadataBrowser.DataProviders;
using DXTools.UI.Core.ViewModel;
using DXTools.Core.CrmSdk;
using System.Collections.ObjectModel;

namespace DXTools.UI.Modules.MetadataBrowser.ViewModels
{
    public class EntityViewModel : ViewModelBase
    {
        private IDataProvider _dataProvider = null;
        private const string HEADER_INFO = "";

        #region Properties

        private IOrderedEnumerable<AttributeMetadata> _attributeList;
        public IOrderedEnumerable<AttributeMetadata> AttributeList
        {
            get
            {
                return _attributeList;
            }
            set
            {
                _attributeList = value;
                RaisePropertyChanged("AttributeList");
            }
        }

        private IOrderedEnumerable<AttributeMetadata> _filteredAttributeList;
        public IOrderedEnumerable<AttributeMetadata> FilteredAttributeList
        {
            get
            {
                return _filteredAttributeList;
            }
            set
            {
                _filteredAttributeList = value;
                RaisePropertyChanged("FilteredAttributeList");
            }
        }

        private IOrderedEnumerable<OneToManyRelationshipMetadata> _relationshipsN1List;
        public IOrderedEnumerable<OneToManyRelationshipMetadata> RelationshipsN1List
        {
            get
            {
                return _relationshipsN1List;
            }
            set
            {
                _relationshipsN1List = value;
                RaisePropertyChanged("RelationshipsN1List");
            }
        }

        private IOrderedEnumerable<ManyToManyRelationshipMetadata> _relationshipsNNList;
        public IOrderedEnumerable<ManyToManyRelationshipMetadata> RelationshipsNNList
        {
            get
            {
                return _relationshipsNNList;
            }
            set
            {
                _relationshipsNNList = value;
                RaisePropertyChanged("RelationshipsNNList");
            }
        }

        private IOrderedEnumerable<OneToManyRelationshipMetadata> _relationships1NList;
        public IOrderedEnumerable<OneToManyRelationshipMetadata> Relationships1NList
        {
            get
            {
                return _relationships1NList;
            }
            set
            {
                _relationships1NList = value;
                RaisePropertyChanged("Relationships1NList");
            }
        }

        private IOrderedEnumerable<OneToManyRelationshipMetadata> _filteredRelationshipsN1List;
        public IOrderedEnumerable<OneToManyRelationshipMetadata> FilteredRelationshipsN1List
        {
            get
            {
                return _filteredRelationshipsN1List;
            }
            set
            {
                _filteredRelationshipsN1List = value;
                RaisePropertyChanged("FilteredRelationshipsN1List");
            }
        }

        private IOrderedEnumerable<ManyToManyRelationshipMetadata> _filteredRelationshipsNNList;
        public IOrderedEnumerable<ManyToManyRelationshipMetadata> FilteredRelationshipsNNList
        {
            get
            {
                return _filteredRelationshipsNNList;
            }
            set
            {
                _filteredRelationshipsNNList = value;
                RaisePropertyChanged("FilteredRelationshipsNNList");
            }
        }

        private IOrderedEnumerable<OneToManyRelationshipMetadata> _filteredRelationships1NList;
        public IOrderedEnumerable<OneToManyRelationshipMetadata> FilteredRelationships1NList
        {
            get
            {
                return _filteredRelationships1NList;
            }
            set
            {
                _filteredRelationships1NList = value;
                RaisePropertyChanged("FilteredRelationships1NList");
            }
        }

        private String _searchText;
        public String SearchText
        {
            get
            {
                return _searchText;
            }
            set
            {
                _searchText = value;
                RaisePropertyChanged("SearchText");
            }
        }

        #endregion

        #region Constructors

         public EntityViewModel(IRegionManager regionManager, IEventAggregator eventAggregator, IUnityContainer container)
            :base(regionManager,eventAggregator,container)
        {
            //this.HeaderInfo = HEADER_INFO;
            
            this.CloseViewCommand = new DelegateCommand<object>(this.CloseView, this.CanCloseView);
            this.SearchCommand = new DelegateCommand<object>(this.Search, this.CanSearch);
            
            _dataProvider = new CRMDataProvider();

        }

         public void InitialiseView(String EntityName)
         {
             
             Action method = () =>
             {
                 this.HeaderInfo = EntityName;
                 RetrieveEntityAttributes(EntityName);
                 RetrieveEntityRelationships(EntityName);

             };

             this.View.Dispatcher.BeginInvoke(method);
         }

        
         #endregion


         #region Mathods

         public DelegateCommand<object> SearchCommand { get; private set; }


        private void CloseView(object commandArg)
        {
            base.CloseView();
        }
        private bool CanCloseView(object commandArg)
        {
            return true;
        }
        private bool CanSearch(object commandArg)
        {
            return true;
        }
     

        #endregion


        #region Load Entities Command

       
        private void RetrieveEntityAttributes(string EntityName)
        {
            IsBusy = true;

            AsyncCallback asyncCallback = (result =>
            {
                IOrganizationService service = (IOrganizationService)result.AsyncState;
                EntityMetadata data = (EntityMetadata)service.EndExecute(result).Results[0].Value;
                
                Action method = () =>
                {
                   
                    var items = from a in data.Attributes
                                orderby a.SchemaName
                                select a;

                    AttributeList = items;

                    LoadAttributeList();

                    IsBusy = false;
                };

                this.View.Dispatcher.BeginInvoke(method);
            });

            this._dataProvider.RetrieveEntityAttributes(EntityName,asyncCallback);
        }


        private void RetrieveEntityRelationships(string EntityName)
        {
            IsBusy = true;

            AsyncCallback asyncCallback = (result =>
            {
                IOrganizationService service = (IOrganizationService)result.AsyncState;
                EntityMetadata data = (EntityMetadata)service.EndExecute(result).Results[0].Value;

                Action method = () =>
                {
                    var manyToOne = from mo in data.ManyToOneRelationships
                                    orderby mo.SchemaName
                                    select mo;

                    var manyToMany = from mm in data.ManyToManyRelationships
                                     orderby mm.SchemaName
                                     select mm;

                    var oneToMany = from om in data.OneToManyRelationships
                                    orderby om.SchemaName
                                    select om;

                    RelationshipsN1List = manyToOne;
                    RelationshipsNNList = manyToMany;
                    Relationships1NList = oneToMany;

                    LoadRelationshipLists();

                    IsBusy = false;
                  
                };

                this.View.Dispatcher.BeginInvoke(method);
            });

            this._dataProvider.RetrieveEntityRelationships(EntityName,asyncCallback);
        }


        private void Search(object commandArg)
        {
            string text = Convert.ToString(commandArg);
            if (!String.IsNullOrEmpty(text))
                SearchText = text;

            LoadAttributeList();
            LoadRelationshipLists();
        }

        private void LoadAttributeList()
        {
            IsBusy = true;

            Action method = () =>
            {
                if (AttributeList != null)
                {
                    var items = from a in AttributeList
                                orderby a.SchemaName
                                select a;

                    if (!String.IsNullOrEmpty(SearchText))
                    {
                        items = from a in AttributeList
                                where a.SchemaName.ToLower().Contains(SearchText.ToLower()) | a.MetadataId.Value.ToString().ToLower().Contains(SearchText.ToLower()) | a.LogicalName.ToLower().Contains(SearchText)
                                orderby a.SchemaName
                                select a;
                    }
                    FilteredAttributeList = items;
                }

                IsBusy = false;
            };

            this.View.Dispatcher.BeginInvoke(method);
        }

        private void LoadRelationshipLists()
        {
            IsBusy = true;

            Action method = () =>
            {
                if (RelationshipsN1List != null)
                {
                     var manyToOne = from mo in RelationshipsN1List
                                orderby mo.SchemaName
                                select mo;

                     if(!String.IsNullOrEmpty(SearchText))
                     {
                            manyToOne = from mo in RelationshipsN1List
                                where mo.SchemaName.ToLower().Contains(SearchText.ToLower()) 
                                | mo.MetadataId.Value.ToString().ToLower().Contains(SearchText.ToLower()) 
                                | mo.ReferencedEntity.ToLower().Contains(SearchText)
                                | mo.ReferencingEntity.ToLower().Contains(SearchText)
                                orderby mo.SchemaName
                                select mo;
                     }
                     FilteredRelationshipsN1List = manyToOne;
               }
                if (RelationshipsNNList != null)
                {
                    var manyToMany = from mm in RelationshipsNNList
                                     orderby mm.SchemaName
                                     select mm;

                    if (!String.IsNullOrEmpty(SearchText))
                    {
                        manyToMany = from mm in RelationshipsNNList
                                     where mm.SchemaName.ToLower().Contains(SearchText.ToLower())
                                     | mm.MetadataId.Value.ToString().ToLower().Contains(SearchText.ToLower())
                                     | mm.Entity1LogicalName.ToLower().Contains(SearchText)
                                     | mm.Entity2LogicalName.ToLower().Contains(SearchText)
                                     orderby mm.SchemaName
                                     select mm;
                    }
                    FilteredRelationshipsNNList = manyToMany;
                }

                if (Relationships1NList != null)
                {
                    var oneToMany = from om in Relationships1NList
                                    orderby om.SchemaName
                                    select om;

                    if (!String.IsNullOrEmpty(SearchText))
                    {
                        oneToMany = from om in Relationships1NList
                                    where om.SchemaName.ToLower().Contains(SearchText.ToLower())
                                    | om.MetadataId.Value.ToString().ToLower().Contains(SearchText.ToLower())
                                    | om.ReferencedEntity.ToLower().Contains(SearchText)
                                    | om.ReferencingEntity.ToLower().Contains(SearchText)
                                    orderby om.SchemaName
                                    select om;
                    }
                    FilteredRelationships1NList = oneToMany;
                }

                IsBusy = false;
            };

            this.View.Dispatcher.BeginInvoke(method);
        }

        #endregion

    }
}
